Im letzten Kapitel haben wir uns damit beschäftigt, wie man C-Programme schreibt,
wie die Programmiersprache aufgebaut ist. Und in Kapitel 3 jetzt möchte ich relativ
kurz darauf eingehen, wie man jetzt von so einem C-Programm, das man mit einem Editor
erstellt hat und in einer Datei abgelegt hat, wie man von diesem C-Programm zu einer Programmausführung,
das nennt man dann ein Prozess, kommt. Im ersten Abschnitt dieses Kapitels möchte ich zusammenfassen,
wie man von einem C-Programm zum ausführbaren Programm, dem sogenannten Executable, kommt.
Also mit den Schritten, die wir zum Teil ja schon kennengelernt haben. Zunächst der C-Präprozessor,
der eine Vorverarbeitung macht, dann der eigentliche Compiler. Der Assemblierschritt
ist heutzutage eigentlich ein inherenter Bestandteil des Compilerschrittes. Man kann
aber diese Assemblerstufe auch noch separat ansteuern und sich auch den Assemblercode vom
Compiler ausgeben lassen und ihn dann weiter übersetzen. Und dann schließlich das Binden
mit anderen Modulen oder das Binden mit Modulen aus Bibliotheken. Und beim Binden unterscheiden wir
auch nochmal das Statische und das Dynamische Binden. Und auch darauf möchte ich im Detail etwas eingehen.
Im zweiten Abschnitt dieses Kapitels werde ich dann die Begriffe Programme und Prozesse kurz
vorstellen und die Speicherorganisation eines Programms im Gegensatz zur Speicherorganisation
eines Prozesses darstellen und kurz einen Überblick darüber geben, was eben passiert,
wenn man ein Programm lädt. Und zwar ein statisch gebundenes oder ein dynamisch gebundenes Programm.
Ja und schließlich im dritten Abschnitt werde ich einen kurzen Überblick über die Prozesszustände
geben, dann wie man einen Prozess erzeugt, wie man ein Programm ausführt und was es
ansonsten noch an Operationen auf Prozessen so gibt. Ja schauen wir uns also erstmal an,
wie man von so einem C-Quellcode zum ausführbaren Programm kommt. Der erste Schritt an dieser
Stelle ist der Präprozessor, den wir uns ja ganz knapp schon mal angeschaut hatten. Die Hauptaufgaben
vom Präprozessor sind das Entfernen von Kommentaren, denn die braucht man zwar für die Lesbarkeit des
Quellcodes, aber der Compiler braucht die gar nicht und das Auswerten von Präprozessoranweisungen.
Es werden also Include-Dateien eingefügt, es werden Makros expandiert und es wird makroabhängiger
Code entfernt für den Fall, dass er eben abhängig von den Makrodefinitionen nicht mit übersetzt
werden soll. Ein Beispiel für so einen makroabhängigen Codeabschnitt habe ich hier dargestellt. Sie
schreiben hin ifdef-debug und endif-debug und alle Zeilen, die zwischen diesem ifdef und endif
stehen, werden nur dann vom Präprozessor in der Quelldatei drin gelassen, wenn dieses makrodebug
definiert ist. Das können Sie natürlich machen, indem Sie einfach vorher define-debug hinschreiben.
Sie müssen ihm keinen Wert geben, es reicht, wenn Sie es einfach definieren. Wenn Sie das irgendwo
am Anfang der Datei hineinschreiben, dann werden alle Codezeilen, die eben zwischen diesem ifdef und
endif stehen, mitkompiliert und wenn Sie das oben rausnehmen, dieses define-debug, dann wird dieser
debug-output eben nicht mehr mitkompiliert. Sie können so ein makro auch beim Kompilieren auf
der Kommandozeile definieren mit "-d debug", und dann brauchen Sie an der Stelle gar nicht die
Quelldatei verändern, sonst können Sie das zum Beispiel auf der Ebene des Makefiles machen.
Das Zwischenergebnis von dem Präprozessorlauf kann man sich auch anschauen. Je nach Compiler gibt
es die Option "-p", da können Sie aus einer Datei.c ein Datei.i erzeugen, indem dann eben die Ausgabe
des Präprozessors nachgeschaut werden kann, oder Sie können mit "-cc-e", Datei.c, auf der
Standalausgabe des Compilers den Präprozessor-output ausgeben lassen und den dann irgendwo
abspeichern, indem Sie zum Beispiel die Ausgabe umlenken. Ja, und wenn der C-Präprozessor dann
sein Vorverarbeitungsergebnis irgendwo intern abgelegt hat, kommt als nächstes der eigentliche
Compiler und der, wenn man es jetzt in einzelnen Schritten betrachtet, übersetzt den C-Code erstmal
in Assembler. Wobei man sagen muss, moderne Compiler heutzutage haben diese Zwischenstufe
nicht mehr, sondern die erzeugen daraus unter Umständen irgendwelche Zwischencodes und aus denen
dann den eigentlichen ausführbaren Maschinencode. Aber konzeptionell kann man sich es also so
vorstellen und früher haben Compiler auch in mehreren Stufen so gearbeitet. Es wird
also erstmal Assembler daraus erzeugt und wie gesagt, also wenn der Assemblercode nicht
explizit angefordert wird, dann passiert ein direkter Übergang vom Kompilieren zum Assemblieren
zu Schritt 3. Das Zwischenergebnis dieses Compiler zu Assembler übersetzens kann man aber
Presenters
Zugänglich über
Offener Zugang
Dauer
00:11:39 Min
Aufnahmedatum
2020-05-25
Hochgeladen am
2020-05-25 09:26:26
Sprache
de-DE